package concurrency.ping_pong.moniteur_synchronized;

public class MoniteurPingPong {

	// ================
	// VARIABLES D'ETAT
	// ----------------
	// Si tour est false alors Pong se bloque pour laisser Ping ecrire
	private boolean tour;
	// ================

	public MoniteurPingPong() {
		// ==============
		// Initialisation
		// --------------
		tour = false;
		// ==============
	}

	// ==============
	// POINT D'ENTREE
	// --------------
	// .wait() et .notify() ne peuvent etre appelees que depuis l'interieur d'un
	// bloc synchronized (dans signature de methode ou bloc)
	private synchronized void ecrirePong() throws InterruptedException {
		// Debut SC
		while (!tour) {
			wait();
		}
		System.out.print("-Pong" + "\n");
		tour = false;
		notify();
		// Fin SC
	}
	// ==============

	// ==============
	// POINT D'ENTREE
	// --------------
	private void ecrirePing() throws InterruptedException {
		synchronized (this) {
			// Debut SC
			while (tour) {
				wait();
			}
			System.out.print("Ping");
			tour = true;
			notify();
			// Fin SC
		}
	}
	// ==============
	
	// ============== FIN MONITEUR // ============== 

	
	
	// ============== PROCESSUS // ==============
	private class Processus implements Runnable {

		private final int repetition;
		private final boolean ping_pong;
		private final Thread thread = new Thread(this);

		public Processus(int repetition, boolean ping_pong) {
			this.repetition = repetition;
			this.ping_pong = ping_pong;
			thread.start();
		}

		@Override
		public void run() {
			try {
				for (int i = 0; i < repetition; i++) {
					if (ping_pong) {
						ecrirePing();
					} else {
						ecrirePong();
					}
				}
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		MoniteurPingPong moniteur = new MoniteurPingPong();
		final int N = 20000;
		Processus ping = moniteur.new Processus(N, true); // true choisi, donc ce sera Ping
		Processus pong = moniteur.new Processus(N, false);
	}
}
